package cn.geminis.auth.engine;

import cn.geminis.auth.model.filter.RegisteredClientFilter;
import cn.geminis.core.exception.CommonException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Arrays;

/**
 * @author puddi
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class GeminisClientRepository implements RegisteredClientRepository {

    private final cn.geminis.auth.model.repository.RegisteredClientRepository repository;

    @Override
    public void save(RegisteredClient registeredClient) {
        if (log.isWarnEnabled()) {
            log.warn("请求注册用户，但未支持该操作");
        }
        throw new CommonException("未支持该操作");
    }

    @Override
    public RegisteredClient findById(String id) {
        var client = this.repository.findById(id)
                .orElseThrow(() -> new CommonException("客户端未注册，id：" + id));
        return createClient(client);
    }

    @Override
    public RegisteredClient findByClientId(String clientId) {
        var client = this.repository
                .findOne(
                        RegisteredClientFilter
                                .builder()
                                .clientId(clientId)
                                .build()
                )
                .orElseThrow(() -> new CommonException("客户端未注册，client id：" + clientId));
        return createClient(client);
    }

    private RegisteredClient createClient(cn.geminis.auth.model.RegisteredClient client) {
        return RegisteredClient.withId(client.getId())
                .clientId(client.getClientId())
                .clientName(client.getClientName())
                .clientSecret(client.getClientSecret())
                .authorizationGrantTypes(type -> Arrays.stream(
                                client.getAuthorizationGrantTypes().split(","))
                        .forEach(value -> type.add(new AuthorizationGrantType(value))))
                .redirectUris(uri -> uri.addAll(Arrays.asList(client.getRedirectUris().split(","))))
                .postLogoutRedirectUris(uri -> uri.addAll(Arrays.asList(client.getPostLogoutRedirectUris().split(","))))
                .tokenSettings(
                        TokenSettings.builder()
                                .accessTokenTimeToLive(Duration.ofMinutes(client.getAccessTokenTime()))
                                .build()
                )
                .scopes(scope -> scope.addAll(Arrays.asList(client.getScopes().split(","))))
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
                .build();
    }
}
